/* Copyright (C) 2024 wlly-lzh
 * Created On 24/03/15
 * Doubly Linked List 双链表(封装)
 * */

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "doublylinkedlist.c"

typedef struct LDLList LDLList;
struct LDLList {
	struct DLinkedList *Head;
	struct DLinkedList *Tail;
	unsigned int Length;
};

void Error_LDLList_Malloc();
void Error_LDLList_Null();
void Error_LDLList_Over();
void AddHead_LDLList(LDLList *List,void *Data);
void AddTail_LDLList(LDLList *List,void *Data);

LDLList * Create_LDLList(){
	LDLList *newList;
	newList=(LDLList *)malloc(sizeof(LDLList));
	if(newList == NULL){
		Error_LDLList_Malloc();
		exit(3);
	}
	newList->Head=newList->Tail=NULL;
	newList->Length=0;
	return newList;
}
void Clear_LDLList(LDLList *List,void (*FreeData)(void *)){
	if(List == NULL){
		Error_LDLList_Null();
		exit(4);
	}
	if(List->Length > 0){
		Destroy_DLinkedList(List->Head,FreeData);
		List->Head=NULL;
		List->Tail=NULL;
		List->Length=0;
	}
}
void Destroy_LDLList(LDLList **List,void (*FreeData)(void *)){
	Clear_LDLList(*List,FreeData);
	free(*List);
	*List=NULL;
}
bool Delete_LDLList(LDLList *List,unsigned int addr,void (*FreeData)(void *)){
	if(List == NULL){
		Error_LDLList_Null();
		exit(4);
	}
	DLinkedList * Del;
	if(addr > 1 && addr < List->Length){
		Delete_DLinkedList(List->Head,addr,FreeData);
		List->Length--;
	}else if(addr == 1){ 
		if(List->Head != NULL){
			Del=List->Head;
			List->Head=Del->TheNext;
			FreeData(Del->Data);
			free(Del);
			List->Length--;
			return true;
		}else{
			return false;
		}
	}else if(addr == List->Length && List->Length >0){
		Del=List->Tail;
		List->Tail=Del->TheLast;
		FreeData(Del->Data);
		free(Del);
		List->Length--;
		return true;
	}else
		Error_LDLList_Over();
	return false;
}
bool Insert_LDLList(LDLList *List,unsigned int addr,void *Data){
	if(List == NULL){
		Error_LDLList_Null();
		exit(4);
	}
	DLinkedList * newList;
	if(List->Length > 0){ // 
		if(addr > 1 && addr <= List->Length){  //在中间插入
			Insert_DLinkedList(List->Head,addr,Data);
			List->Length++;
		}else if(addr == 1){                   //在头部插入
			AddHead_LDLList(List,Data);
		}else if(addr == List->Length+1){      //在尾部插入
			AddTail_LDLList(List,Data);
		}else{
			Error_LDLList_Over();
			return false;
		}
	}else if(addr == 1){
		newList=(DLinkedList *)malloc(sizeof(DLinkedList));
		if(newList == NULL){
			Error_LDLList_Malloc();
			exit(3);
		}
		newList->Data=Data;
		newList->TheLast=newList->TheNext=NULL;
		List->Head=List->Tail=newList;
		List->Length++;
	}else
		Error_LDLList_Over();
	return false;
}
void AddHead_LDLList(LDLList *List,void *Data){
	if(List == NULL){
		Error_LDLList_Null();
		exit(4);
	}
	DLinkedList * addList=(DLinkedList *)malloc(sizeof(DLinkedList));
	if(addList == NULL){
		Error_LDLList_Malloc();
		exit(3);
	}// 0<1>2 0<2>3 2<3>4 3<4>0
	 //   ^      
	addList->Data=Data;
	addList->TheLast=NULL;
	addList->TheNext=List->Head;
	List->Head->TheLast=addList;
	List->Head=addList;
	if(List->Length == 0){ // 注意未写入数据的情况
		List->Tail=addList;
	}
	List->Length++;
}
void AddTail_LDLList(LDLList *List,void *Data){
	if(List == NULL){
		Error_LDLList_Null();
		exit(4);
	}
	DLinkedList * addList=(DLinkedList *)malloc(sizeof(DLinkedList));
	if(addList == NULL){
		Error_LDLList_Malloc();
		exit(3);
	}
	addList->Data=Data;
	addList->TheNext=NULL;
	addList->TheLast=List->Tail;
	List->Tail->TheNext=addList;
	List->Tail=addList;
	if(List->Length == 0){ // 注意表为空的情况
		List->Head=addList;
	}
	List->Length++;
}// 0<1>2 1<2>3 2<3>0 3<4>0
 //               ^     
bool GetItem_LDLList(LDLList *List,unsigned int addr,void **Data){
	if(List == NULL){
		Error_LDLList_Null();
		exit(4);
	}
	if(addr > 0 && addr < List->Length){
		DLinkedList * getlist=List->Head;
		for(int i=1; i<addr; ++i){
			getlist=getlist->TheNext;
		}
		*(Data)=getlist->Data;
	}
	else if(addr == List->Length && addr > 0){ // 预防 add=Length=0
		*Data=List->Tail->Data;
	}
	else{
		printf("add=%d\n",addr);
		Error_LDLList_Over();
		return false;
	}
	return true;
}
bool Update_LDLList(LDLList *List,unsigned int addr,void *Data,
		void (*FreeData)(void *)){
	if(List == NULL){
		Error_LDLList_Null();
		exit(4);
	}
	if(addr > 0 && addr <= List->Length){
		DLinkedList * Update=List->Head;
		for(unsigned int i=1; i<addr; ++i){
			Update=Update->TheNext;
		}
		(*FreeData)(Update->Data);
		Update->Data=Data;
		return true;
	}else{
		Error_LDLList_Over();
		return false;
	}
}
unsigned int Length_LDLList(const LDLList *List){
	return List->Length;
}
#ifdef _LINUX_PLATFORM_
void Error_LDLList_Malloc(){
	fprintf(stderr,"\e[31mliblds/LDLList: Malloc False!\e[0m\n");
}
void Error_LDLList_Null(){
	fprintf(stderr,"\e[31mliblds/LDLList: The Parameter is Null!\e[0m\n");
}
void Error_LDLList_Over(){
	fprintf(stderr,"\e[31mliblds/LDLList: Addr over the bounds!\e[0m\n");
}
#else
void Error_LDLList_Malloc(){
	fprintf(stderr,"liblds/LDLList: Malloc False!\n");
}
void Error_LDLList_Null(){
	fprintf(stderr,"liblds/LDLList: The Parameter is Null!\n");
}
void Error_LDLList_Over(){
	fprintf(stderr,"liblds/LDLList: Addr over the bounds!\n");
}
#endif
